import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

# 创建一个蓝图对象，命名为auth，将路由映射前缀设为/auth
bp = Blueprint('auth', __name__, url_prefix='/auth')

# 注册视图函数，用于显示注册页面
@bp.route('/register', methods=('GET', 'POST'))
def register():
    if request.method == 'POST':
        # 获取用户名和密码
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        if not username:
            error = '必须填写用户名。'
        elif not password:
            error = '必须填写密码。'
        elif db.execute(
            'SELECT id FROM user WHERE username = ?', (username,)
        ).fetchone() is not None:
            error = '用户名 {} 已经存在。'.format(username)

        if error is None:
            # 插入新用户到数据库中
            db.execute(
                'INSERT INTO user (username, password) VALUES (?, ?)', (username, generate_password_hash(password))
            )
            db.commit()
            # 注册成功后重定向到登录页面
            return redirect(url_for('auth.login'))

        # 将错误信息显示在页面上
        flash(error)

    # 渲染注册页面
    return render_template('auth/register.html')

# 登录视图函数，用于显示登录页面和处理登录请求
@bp.route('/login', methods=('GET', 'POST'))
def login():
    if request.method == 'POST':
        # 获取用户名和密码
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        user = db.execute(
            'SELECT * FROM user WHERE username = ?', (username,) 
        ).fetchone()

        if user is None:
            error = '用户名 {} 不存在！'.format(username)
        elif not check_password_hash(user['password'], password):
            error = '密码错误！'

        if error is None:
            # 登录成功后将用户 ID 存储在会话中
            session.clear()
            session['user_id'] = user['id']
            # 登录成功后重定向到首页
            return redirect(url_for('index'))

        # 将错误信息显示在页面上
        flash(error)

    # 渲染登录页面
    return render_template('auth/login.html')

# 注销视图函数，用于处理注销请求
@bp.route('/logout')
def logout():
    # 清空会话中的用户 ID
    session.clear()
    # 注销成功后重定向到首页
    return redirect(url_for('index'))

# 在用户访问其他视图函数之前，检查用户是否已登录
@bp.before_app_request
def load_logged_in_user():
    user_id = session.get('user_id')

    if user_id is None:
        g.user = None
    else:
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id =?', (user_id,)
        ).fetchone()

# 定义一个装饰器，用于检查用户是否已登录
def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            # 如果用户未登录，则重定向到登录页面
            return redirect(url_for('auth.login'))
        return view(**kwargs)
    return wrapped_view